home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / os2 / ssaver26.zip / SAMPLE.ZIP / SAMPLE.C < prev    next >
C/C++ Source or Header  |  1996-10-02  |  23KB  |  687 lines

  1. /*
  2.     sample.c
  3.     sample saver module C source file version 2.6
  4.     (C) 1993-96 Siegfried Hanisch
  5. */
  6.  
  7. #define INCL_DOS
  8. #define INCL_DOSERRORS
  9. #define INCL_WIN
  10. #define INCL_GPI
  11. #include <os2.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <limits.h>
  16. #include <process.h>
  17. #include <time.h>
  18.  
  19. #include "sample.h"
  20.  
  21.  
  22. // ===== preprocessor definitions
  23.  
  24. #define MODULEVERSION        0x00020006
  25. #define STACKSIZE        (64*1024)
  26. #define SAVER_NAME_MAXLEN    32
  27. #define ZORDERTIMERSTEP     30000L
  28. #define FUNCTION_CONFIGURE    1
  29. #define FUNCTION_STARTSAVER    2
  30. #define FUNCTION_STOPSAVER    3
  31. #define FUNCTION_QUERYNAME    4
  32. #define FUNCTION_QUERYENABLED    5
  33. #define FUNCTION_SETENABLED    6
  34. #define FUNCTION_SETINIFILENAME 7
  35. #define WMP_MODULECRASH     WM_USER + 13
  36. #define CONFIGURATION_DEFAULT_ANIMATIONSPEED 4    // 0=slow .. 4=fast
  37. /*
  38.     $$$$$ insert code here $$$$$
  39.     This is the place for your preprocessor definitions.
  40.  
  41.     $$$$$ for example $$$$$
  42. #define CONFIGURATION_MINIMUM_COUNT 1
  43. #define CONFIGURATION_DEFAULT_COUNT 32
  44. #define CONFIGURATION_MAXIMUM_COUNT 100
  45. */
  46.  
  47. // ===== prototypes
  48.  
  49. void    EXPENTRY SAVER_PROC(int function, HAB _hab, HWND hwndOwner, char *appname, void *buffer);
  50. static    MRESULT EXPENTRY SaverWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  51. static    MRESULT EXPENTRY ConfigureDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  52. #if defined(__IBMC__) || defined(__EMX__)
  53. static    void    _Optlink draw_thread(void *args);
  54. static    void    _Optlink priority_thread(void *args);
  55. #elif defined(__BORLANDC__)
  56. static    void    _USERENTRY draw_thread(void *args);
  57. static    void    _USERENTRY priority_thread(void *args);
  58. #endif
  59. static    void    load_configuration_data(void);
  60. static    void    write_profile_data(void);
  61. static    ULONG    query_profile_data(void);
  62. ULONG    GPFHandler(PEXCEPTIONREPORTRECORD pxcptrec, PEXCEPTIONREGISTRATIONRECORD prr, PCONTEXTRECORD pcr, PVOID pv);
  63. void    print_contextrecord(FILE *logfile, PCONTEXTRECORD pcr);
  64.  
  65.  
  66. // ===== global data
  67.  
  68. ULONG    MODULESOURCE_VERSION = 0x00020006;    // EXPORTED: ScreenSaver 2.6/Pro 1.3 module source code (do not change)
  69.  
  70. static    LONG    screenSizeX = 0;        // screen size x
  71. static    LONG    screenSizeY = 0;        // screen size y
  72. static    HWND    hwndSaver = NULLHANDLE;     // saver window handle
  73. static    HMODULE hmodDLL = NULLHANDLE;        // saver module dll handle
  74. static    HWND    hwndApplication = NULLHANDLE;    // window handle if ScreenSaver options dialog (main window)
  75. static    char    *application_name;        // name of ScreenSaver app
  76. static    TID    tidDraw;            // drawing-thread ID
  77. static    TID    tidPriority;            // priority regulation thread ID
  78. static    HDC    hdc;                // device context handle
  79. static    HPS    hps;                // presentation space handle
  80. static    HAB    hab;                // anchor block handle
  81. static    BOOL    low_priority = TRUE;        // low-priority flag
  82. static    BOOL    configuration_data_loaded = FALSE; // config data loaded flag
  83. static    volatile BOOL stop_draw_thread;     // stop flag
  84. static    char    modulename[SAVER_NAME_MAXLEN+1]; // module name buffer
  85. static    volatile BOOL stop_priority_thread = FALSE;
  86. static    char    ini_filename[CCHMAXPATH] = "";  // name of INI file if other than OS2.INI
  87.  
  88. static    struct    _configuration_data {
  89.     ULONG    version;
  90.     char    modulename[SAVER_NAME_MAXLEN+1];
  91.     BOOL    enabled;
  92.     int    animation_speed;
  93. /*
  94.     $$$$$ insert code here $$$$$
  95.     If your saver module needs some additional configuration data,
  96.     insert it here. It is automatically loaded and saved.
  97.  
  98.     $$$$$ for example $$$$$
  99.     int    count;
  100. */
  101. } configuration_data;
  102.  
  103.  
  104. // ===== code
  105.  
  106. /*
  107.     GPFHandler - general protection fault exception handler
  108.     There should be no reason to alter the code.
  109. */
  110.  
  111. ULONG    GPFHandler(PEXCEPTIONREPORTRECORD pxcptrec, PEXCEPTIONREGISTRATIONRECORD prr, PCONTEXTRECORD pcr, PVOID pv)
  112. {
  113.     if(pxcptrec->ExceptionNum == XCPT_ACCESS_VIOLATION){
  114.         time_t    t;
  115.         FILE    *logfile = fopen("crash.log", "a");
  116.         t = time(NULL);
  117.         fprintf(logfile, "Module %s crashed at %s", modulename, ctime(&t));
  118.         fprintf(logfile, "ACCESS VIOLATION (xcpt # 0x%X)\n", (unsigned int)pxcptrec->ExceptionNum);
  119.         fprintf(logfile, "xcpt info[0] flags = 0x%02X\n", (unsigned int)pxcptrec->ExceptionInfo[0]);
  120.         fprintf(logfile, "xcpt info[1] faultaddr = 0x%08X\n", (unsigned int)pxcptrec->ExceptionInfo[1]);
  121.         print_contextrecord(logfile, pcr);
  122.         fclose(logfile);
  123.         WinPostMsg(hwndApplication, WMP_MODULECRASH, MPVOID, MPVOID);
  124.         _endthread();
  125. //          DosExit(EXIT_THREAD, 1);
  126.     }
  127.     return(XCPT_CONTINUE_SEARCH);
  128. }
  129.  
  130. /*
  131.     print_contextrecord - helper function for GPFHandler
  132.     There should be no reason to alter the code.
  133. */
  134. void    print_contextrecord(FILE *logfile, PCONTEXTRECORD pcr)
  135. {
  136.     fprintf(logfile, "  ContextFlags = 0x%08lX\n", pcr->ContextFlags);
  137.     if(pcr->ContextFlags & CONTEXT_SEGMENTS){
  138.         fprintf(logfile, "  GS = 0x%08lX\n", pcr->ctx_SegGs);
  139.         fprintf(logfile, "  FS = 0x%08lX\n", pcr->ctx_SegFs);
  140.         fprintf(logfile, "  ES = 0x%08lX\n", pcr->ctx_SegEs);
  141.         fprintf(logfile, "  DS = 0x%08lX\n", pcr->ctx_SegDs);
  142.     }
  143.     if(pcr->ContextFlags & CONTEXT_INTEGER){
  144.         fprintf(logfile, "  EAX = 0x%08lX\n", pcr->ctx_RegEax);
  145.         fprintf(logfile, "  EBX = 0x%08lX\n", pcr->ctx_RegEbx);
  146.         fprintf(logfile, "  ECX = 0x%08lX\n", pcr->ctx_RegEcx);
  147.         fprintf(logfile, "  EDX = 0x%08lX\n", pcr->ctx_RegEdx);
  148.         fprintf(logfile, "  EDI = 0x%08lX\n", pcr->ctx_RegEdi);
  149.         fprintf(logfile, "  ESI = 0x%08lX\n", pcr->ctx_RegEsi);
  150.     }
  151.     if(pcr->ContextFlags & CONTEXT_CONTROL){
  152.         fprintf(logfile, "  SS = 0x%08lX\n", pcr->ctx_SegSs);
  153.         fprintf(logfile, "  ESP = 0x%08lX\n", pcr->ctx_RegEsp);
  154.         fprintf(logfile, "  EBP = 0x%08lX\n", pcr->ctx_RegEbp);
  155.         fprintf(logfile, "  EFLAGS = 0x%08lX\n", pcr->ctx_EFlags);
  156.         fprintf(logfile, "  CS = 0x%08lX\n", pcr->ctx_SegCs);
  157.         fprintf(logfile, "  EIP = 0x%08lX\n", pcr->ctx_RegEip);
  158.     }
  159. }
  160.  
  161. /*
  162.     SAVER_PROC
  163.     This is the entry point into the saver module that is called by
  164.     the ScreenSaver program.
  165.     There should be no reason to alter the code.
  166.     Depending on the requested function, the following tasks
  167.     are performed:
  168.     * set the name of the INI file to store and query settings
  169.     * call the configuration dialog of the saver module
  170.     * copy the name of the saver module into the supplied buffer
  171.     * tell if the saver module is enabled
  172.     * set the "enabled" state of the saver module
  173.     * start the saver
  174.     * stop the saver
  175.     Note that before any processing is done, module configuration data is
  176.     loaded from the INI-files.
  177. */
  178. void    EXPENTRY SAVER_PROC(int function, HAB _hab, HWND hwndOwner, char *appname, void *buffer)
  179. {
  180. #if defined(__BORLANDC__)
  181.     extern ULONG __os2hmod;
  182.     hmodDLL = __os2hmod;
  183. #endif
  184.     hab = _hab;
  185.     application_name = appname;
  186.     hwndApplication = hwndOwner;
  187.     // load all configuration data from INI-file
  188.     if(function != FUNCTION_SETINIFILENAME)
  189.         load_configuration_data();
  190.     switch(function){
  191.     case FUNCTION_SETINIFILENAME:
  192.         if(buffer != NULL)
  193.             strcpy(ini_filename, (char *)buffer);
  194.         else
  195.             strcpy(ini_filename, "");
  196.         return;
  197.     case FUNCTION_CONFIGURE:
  198.         // call the configuration dialog
  199.         WinDlgBox(HWND_DESKTOP, hwndOwner, ConfigureDlgProc,
  200.           hmodDLL, IDD_CONFIGURE, application_name);
  201.         return;
  202.     case FUNCTION_STARTSAVER:
  203.         // start the saver
  204.         // get "low priority" state from supplied buffer (BOOL *)
  205.         low_priority = *((BOOL *)buffer);
  206.         // query size of screen
  207.         screenSizeX = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  208.         screenSizeY = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  209.         // register window class for the saver window
  210.         WinRegisterClass(hab, (PSZ)modulename,
  211.           (PFNWP)SaverWindowProc, 0, 0);
  212.         // create the saver window
  213.         hwndSaver = WinCreateWindow(HWND_DESKTOP, (PSZ)modulename,
  214.           (PSZ)NULL, WS_VISIBLE, 0, 0, screenSizeX, screenSizeY,
  215.           HWND_DESKTOP, HWND_TOP, 0, NULL, NULL);
  216.         return;
  217.     case FUNCTION_STOPSAVER:
  218.         // stop the saver
  219.         if(low_priority){
  220.             stop_priority_thread = TRUE;
  221.             DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 0, tidPriority);
  222.             DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 0, tidDraw);
  223.             DosWaitThread(&tidPriority, DCWW_WAIT);
  224. //              DosKillThread(tidPriority);    ***** kills thread 1 under OS/2 2.11
  225.         }
  226.         // tell drawing-thread to stop
  227.         stop_draw_thread = TRUE;
  228.         if(DosWaitThread(&tidDraw, DCWW_NOWAIT) == ERROR_THREAD_NOT_TERMINATED){
  229.             // if priority of drawing-thread was set to idle time
  230.             // priority, set it back to normal value
  231.             DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, tidDraw);
  232.             // wait until drawing-thread has ended
  233.             DosWaitThread(&tidDraw, DCWW_WAIT);
  234.         }
  235.  
  236.         if(hwndSaver != NULLHANDLE){
  237.             // move saver window to front
  238.             WinSetWindowPos(hwndSaver, HWND_TOP,
  239.               0, 0, 0, 0, SWP_ZORDER);
  240.             // destroy saver window
  241.             WinDestroyWindow(hwndSaver);
  242.             hwndSaver = NULLHANDLE;
  243.         }
  244.         return;
  245.     case FUNCTION_QUERYNAME:
  246.         // copy module name to supplied buffer (CHAR *)
  247.         strcpy(buffer, modulename);
  248.         return;
  249.     case FUNCTION_QUERYENABLED:
  250.         // copy "enabled" state to supplied buffer (BOOL *)
  251.         *((BOOL *)buffer) = configuration_data.enabled;
  252.         return;
  253.     case FUNCTION_SETENABLED:
  254.         // get new "enabled" state from supplied buffer (BOOL *)
  255.         configuration_data.enabled = *((BOOL *)buffer);
  256.         write_profile_data();
  257.         return;
  258.     }
  259.  
  260.     // illegal function request
  261.     WinAlarm(HWND_DESKTOP, WA_ERROR);
  262.     return;
  263. }
  264.  
  265. #if !defined(__BORLANDC__)
  266. /*
  267.     _DLL_InitTerm
  268.     This procedure is called at DLL initialization and termination.
  269.     There should be no reason to alter the code.
  270. */
  271. ULONG    _DLL_InitTerm(HMODULE hmod, ULONG flag)
  272. {
  273.     switch(flag){
  274.     case 0: // initializing DLL
  275.         hmodDLL = hmod;
  276.         return 1;
  277.     case 1: // terminating DLL
  278.         return 1;
  279.     default:
  280.         // return error
  281.         return 0;
  282.     }
  283. }
  284. #endif
  285.  
  286. /*
  287.     ConfigureDlgProc
  288.     This is the dialog procedure for the module configuration dialog.
  289.     The dialog contains a check box for enabling/disabling the module
  290.     and two push buttons ("OK" and "Cancel") to close/cancel the dialog.
  291.     Since version 1.2, it contains a slider to set the animation speed;
  292.     if you don't want this slider, change the '#if 0' line in the
  293.     WM_INITDLG part of this dialog procedure.
  294.  
  295.     This is enough for simple saver modules, but can easily be expanded
  296.     for more saver modules that need more settings.
  297. */
  298. MRESULT EXPENTRY ConfigureDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  299. {
  300.     char    buf[sizeof(modulename)+20];
  301.     static    HWND    hwndEnabled;
  302.     static    HWND    hwndSpeed;
  303. /*
  304.     $$$$$ insert code here $$$$$
  305.     If you need additional data for dialog processing, insert it here.
  306.  
  307.     $$$$$ for example $$$$$
  308.     static    HWND    hwndCount;
  309. */
  310.     switch(msg){
  311.     case WM_INITDLG:
  312.         // set titlebar of the dialog window
  313.         // to "MODULENAME configuration"
  314.         strcpy(buf, modulename);
  315.         strcat(buf, " configuration");
  316.         WinSetWindowText(hwnd, (PSZ)buf);
  317.  
  318.         // get window handles of the dialog controls
  319.         // and set initial state of the controls
  320.         hwndEnabled = WinWindowFromID(hwnd, IDC_ENABLED);
  321.         WinSendMsg(hwndEnabled, BM_SETCHECK,
  322.           MPFROMLONG(configuration_data.enabled), MPVOID);
  323.         hwndSpeed = WinWindowFromID(hwnd, IDC_SPEED);
  324.         WinSendMsg(hwndSpeed, SLM_SETTICKSIZE, MPFROM2SHORT(SMA_SETALLTICKS, 3), MPVOID);
  325.         WinSendMsg(hwndSpeed, SLM_SETSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), MPFROMLONG(configuration_data.animation_speed));
  326.         WinSendMsg(hwndSpeed, SLM_SETSCALETEXT, MPFROMSHORT(0), MPFROMP("slow"));
  327.         WinSendMsg(hwndSpeed, SLM_SETSCALETEXT, MPFROMSHORT(4), MPFROMP("fast"));
  328. /*
  329.         $$$$$ insert code here $$$$$
  330.         Get window handles of your dialog controls.
  331.         Set initial state of your controls.
  332.  
  333.         $$$$$ for example $$$$$
  334.         hwndCount = WinWindowFromID(hwnd, IDC_COUNT);
  335.         WinSendMsg(hwndCount, SPBM_SETLIMITS, (MPARAM)CONFIGURATION_MAXIMUM_COUNT, (MPARAM)CONFIGURATION_MINIMUM_COUNT);
  336.         WinSendMsg(hwndCount, SPBM_SETCURRENTVALUE, MPFROMLONG(configuration_data.count), MPVOID);
  337. */
  338. #if 0        // if yoy don't use speed setting, replace the 0 with a 1
  339.         WinShowWindow(WinWindowFromID(hwnd, IDC_SPEED), FALSE);
  340.         WinShowWindow(WinWindowFromID(hwnd, IDC_SPEEDTEXT), FALSE);
  341. #endif
  342.         // return FALSE since we did not change the focus
  343.         return (MRESULT)FALSE;
  344.     case WM_COMMAND:
  345.         switch(SHORT1FROMMP(mp1)){
  346.         case IDC_OK:
  347.             // OK button was pressed. query the control settings
  348.             configuration_data.enabled = SHORT1FROMMR(WinSendMsg(hwndEnabled, BM_QUERYCHECK, MPVOID, MPVOID));
  349.             configuration_data.animation_speed = SHORT1FROMMR(WinSendMsg(hwndSpeed, SLM_QUERYSLIDERINFO, MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE), MPVOID));
  350. /*
  351.             $$$$$ insert code here $$$$$
  352.             Query control settings of your controls.
  353.  
  354.             $$$$$ for example $$$$$
  355.             WinSendMsg(hwndCount, SPBM_QUERYVALUE, MPFROMP(&configuration_data.count), MPFROM2SHORT(0, SPBQ_ALWAYSUPDATE));
  356. */
  357.             // write all configuration data to INI-file
  358.             write_profile_data();
  359.  
  360.             // end dialog
  361.             WinDismissDlg(hwnd, TRUE);
  362.             return (MRESULT)0;
  363.         case IDC_CANCEL:
  364.             // dialog was cancelled; end it
  365.             WinDismissDlg(hwnd, FALSE);
  366.             return (MRESULT)0;
  367.         default:
  368.             return (MRESULT)0;
  369.         }
  370.     }
  371.     return WinDefDlgProc(hwnd, msg, mp1, mp2);
  372. }
  373.  
  374. /*
  375.     SaverWindowProc
  376.     This is the window procedure of the screen-size window that is
  377.     created when the saver starts.
  378.     There should be no reason to alter the code.
  379.     Note that we do not process WM_PAINT messages. They are forwarded to
  380.     the default window procedure, which just validates the window area
  381.     and does no drawing. All drawing to the window should be done in
  382.     the drawing-thread. Therefore, if you want to blank the screen before
  383.     drawing on it for instance, issue a WinFillRect call at the beginning
  384.     of your drawing-thread.
  385. */
  386. MRESULT EXPENTRY SaverWindowProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  387. {
  388.     static    SIZEL    pagesize={0, 0};
  389.     switch(msg){
  390.     case WM_CREATE:
  391.         // reset the "stop" flag
  392.         stop_draw_thread = FALSE;
  393.         // store window handle
  394.         hwndSaver = hwnd;
  395.         // get hdc and create normal presentation space
  396.         hdc = WinOpenWindowDC(hwnd);
  397.         hps = GpiCreatePS(hab, hdc, &pagesize, GPIA_ASSOC|PU_PELS|GPIT_NORMAL);
  398.         // start the drawing-thread
  399. /*
  400.         $$$$$ note $$$$$
  401.         Some compilers use another parameter ordering for
  402.         _beginthread. The _beginthread call below works with EMX,
  403.         ICC and BCC. Check your compiler docs for other compilers.
  404. */
  405. #if defined(__BORLANDC__)
  406.         // for Borland C++
  407.         tidDraw = _beginthread(draw_thread, STACKSIZE, NULL);
  408. #elif defined(__EMX__) || defined(__IBMC__)
  409.         // for EMX and ICC
  410.         tidDraw = _beginthread(draw_thread, NULL, STACKSIZE, NULL);
  411. #endif
  412.         // create thread to control priority of drawing thread
  413.         if(low_priority){
  414.             stop_priority_thread = FALSE;
  415.             DosCreateThread(&tidPriority, (PFNTHREAD)priority_thread, 0, 2L, 1000);
  416.         }
  417.         // create timer that moves the saver window to top regularly
  418.         WinStartTimer(hab, hwndSaver, IDT_ZORDERTIMER, ZORDERTIMERSTEP);
  419.         return (MRESULT)FALSE;
  420.     case WM_TIMER:
  421.         if(SHORT1FROMMP(mp1) == IDT_ZORDERTIMER){
  422.             // move saver window to top
  423.             WinSetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER);
  424.             return (MRESULT)0;
  425.         }
  426.         break;
  427.     case WM_DESTROY:
  428.         // destroy the presentation space
  429.         GpiDestroyPS(hps);
  430.         // stop the z-order timer
  431.         WinStopTimer(hab, hwndSaver, IDT_ZORDERTIMER);
  432.         break;
  433.     case WM_PAINT:
  434.         // just validate the update area. all drawing is done
  435.         // in the drawing-thread.
  436.         return WinDefWindowProc(hwnd, msg, mp1, mp2);
  437.     }
  438.     return WinDefWindowProc(hwnd, msg, mp1, mp2);
  439. }
  440.  
  441. /*
  442.     priority_thread
  443.     This thread controls the priority of the drawing thread.
  444.     With these changes, if a saver module runs on low priority (this is
  445.     the default setting), it rises to normal priority twice a second
  446.     for 0.1 seconds. This should solve the problem that, when very
  447.     time-consuming processes were running, the module seemed not to become
  448.     active at all (in fact it became active, but did not get enough CPU
  449.     time to do its saver action).
  450.     There should be no reason to alter the code.
  451. */
  452. void    priority_thread(void *args)
  453. {
  454.     DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
  455.     for(;!stop_priority_thread;){
  456.         int    i;
  457.         DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 0, tidDraw);
  458.         DosSleep(100);
  459.         DosSetPriority(PRTYS_THREAD, PRTYC_IDLETIME, 0, tidDraw);
  460.         for(i=0;!stop_priority_thread && i<4;i++)
  461.             DosSleep(100);
  462.     }
  463. }
  464.  
  465. /*
  466.     load_configuration_data
  467.     Load all module configuration data from the INI-file into the
  468.     configuration_data structure, if not done already loaded.
  469. */
  470. void    load_configuration_data(void)
  471. {
  472.     if(configuration_data_loaded == FALSE){
  473.         // data not loaded yet
  474.         ULONG    size;
  475.         // get name of the saver module (stored as resource string)
  476.         if(WinLoadString(hab, hmodDLL, IDS_MODULENAME,
  477.           SAVER_NAME_MAXLEN, (PSZ)modulename) == 0){
  478.             // resource string not found. indicate error by
  479.             // setting module name to empty string (the name
  480.             // "" is interpreted as an error by SSDLL.DLL and
  481.             // the module does not show up in the list box).
  482.             strcpy(modulename, "");
  483.             return;
  484.         }
  485.         // load data from INI-file. the key name is the name of the
  486.         // saver module
  487.         size = query_profile_data();
  488.         if(size != sizeof(configuration_data)
  489.           || configuration_data.version != MODULEVERSION
  490.           || strncmp(modulename, configuration_data.modulename, sizeof(modulename)) != 0){
  491.             // if entry is not found or entry has invalid size or
  492.             // entry has wrong version number, create a new entry
  493.             // with default values and write it to the INI-file
  494.             configuration_data.version = MODULEVERSION;
  495.             configuration_data.enabled = TRUE;
  496.             configuration_data.animation_speed = CONFIGURATION_DEFAULT_ANIMATIONSPEED;
  497.             strncpy(configuration_data.modulename, modulename, sizeof(configuration_data.modulename));
  498. /*
  499.             $$$$$ insert code here $$$$$
  500.             If you have added data to the configuration_data
  501.             structure, insert code here to set the default
  502.             values for your data items.
  503.  
  504.             $$$$$ for example $$$$$
  505.             configuration_data.count = CONFIGURATION_DEFAULT_COUNT;
  506. */
  507.             write_profile_data();
  508.         }
  509.         configuration_data_loaded = TRUE;
  510.     }
  511. }
  512.  
  513. /*
  514.     write_profile_data
  515.     Write configuration data to the selected INI file.
  516.     There should be no reason to alter the code.
  517. */
  518. void    write_profile_data()
  519. {
  520. //OLD CODE      if(*ini_filename)
  521. //OLD CODE          return;      // don't write if not OS2.INI
  522. //OLD CODE      PrfWriteProfileData(HINI_USER, (PSZ)application_name, (PSZ)modulename, (PSZ)&configuration_data, sizeof(configuration_data));
  523.     HINI   ini_file = HINI_USER;
  524.     if(*ini_filename){
  525.         ini_file = PrfOpenProfile(hab, (PSZ)ini_filename);
  526.         if(ini_file == NULLHANDLE)
  527.             ini_file = HINI_USER;
  528.     }else
  529.         ini_file = HINI_USER;
  530.     PrfWriteProfileData(ini_file, (PSZ)application_name, (PSZ)modulename, (PSZ)&configuration_data, sizeof(configuration_data));
  531.     if(ini_file != HINI_USER)
  532.         PrfCloseProfile(ini_file);
  533. }
  534.  
  535. /*
  536.     query_profile_data
  537.     Read configuration data from the selected INI file.
  538.     There should be no reason to alter the code.
  539. */
  540. ULONG    query_profile_data()
  541. {
  542.     HINI    ini_file;
  543.     BOOL    fSuccess;
  544.     ULONG    size;
  545.  
  546.     if(*ini_filename){
  547.         ini_file = PrfOpenProfile(hab, (PSZ)ini_filename);
  548.         if(ini_file == NULLHANDLE)
  549.             ini_file = HINI_USER;
  550.     }else
  551.         ini_file = HINI_USER;
  552.  
  553.     size = sizeof(configuration_data);
  554.     fSuccess = PrfQueryProfileData(ini_file,
  555.       (PSZ)application_name, (PSZ)modulename,
  556.       (PSZ)&configuration_data, &size);
  557.  
  558.     if(ini_file != HINI_USER)
  559.         PrfCloseProfile(ini_file);
  560.     if(fSuccess == FALSE)
  561.         return 0;
  562.     else
  563.         return size;
  564. }
  565.  
  566. /*
  567.     draw_thread
  568.     This is the drawing-thread.
  569.     You have a valid presentation space handle (hps), a valid window
  570.     handle (hwndSaver) and the configuration_data structure is loaded.
  571.     The screen size is stored in "screenSizeX" and "screenSizeY".
  572.     IMPORTANT NOTE 1:
  573.     You must check the "stop_draw_thread" flag regularly. If it is set,
  574.     free all resources you have allocated and call _endthread (or just
  575.     return) to end the drawing-thread.
  576.     IMPORTANT NOTE 2:
  577.     If the "low_priority" flag is NOT set (that means you run with
  578.     regular priority, sharing CPU usage with other programs), you should
  579.     call DosSleep(x) with "x" set at least to 1 as often as possible, to
  580.     allow other programs to do their work. A screen saver should not eat
  581.     up other program's CPU time!
  582.     IMPORTANT NOTE 3:
  583.     For some of the PM calls to work properly, your thread needs an
  584.     own HAB and maybe even a message queue. You have to get and release
  585.     both of them here if you use such PM calls.
  586.  
  587.     The following sample code is from the "Pyramids" module that comes
  588.     with the ScreenSaver distribution.
  589.     It selects a random color and a random point on the screen, then
  590.     draws lines in the selected color from each corner of the screen
  591.     to the selected point (looks somewhat like a pyramid).
  592.     It remembers a number of points (this number can be set in the
  593.     configuration dialog). Having filled the point memory, it redraws
  594.     the "oldest" visible pyramid in black. This has the effect that more
  595.     and more pixels on the screen get black, only a few constantly
  596.     changing colored lines remain.
  597. */
  598. void    draw_thread(void *args)
  599. {
  600. /*
  601.     $$$$$ replace or change the following example code $$$$$
  602.     int    i, j;
  603.     POINTL    pt_corner[4];
  604.     BOOL    point_buffer_filled;
  605.     POINTL    *pt;
  606.  
  607.     HAB    drawingthread_hab = WinInitialize(0);
  608.     HMQ    drawingthread_hmq = WinCreateMsgQueue(drawingthread_hab, 0);
  609.  
  610.     EXCEPTIONREGISTRATIONRECORD    xcpthand = { (PEXCEPTIONREGISTRATIONRECORD)0, GPFHandler };
  611.     DosSetExceptionHandler(&xcpthand) ;
  612.  
  613.     // random seed (needed for each thread)
  614.     srand(WinGetCurrentTime(hab));
  615.  
  616.     i = 0;
  617.     point_buffer_filled = FALSE;
  618.     // allocate stack memory for circular point buffer
  619.     pt = alloca(configuration_data.count * sizeof(POINTL));
  620.     if(pt == NULL){
  621.         DosUnsetExceptionHandler(&xcpthand);
  622.         _endthread();
  623.     }
  624.  
  625.     // set the corner coordinates
  626.     pt_corner[0].x = 0;
  627.     pt_corner[0].y = 0;
  628.     pt_corner[1].x = 0;
  629.     pt_corner[1].y = screenSizeY-1;
  630.     pt_corner[2].x = screenSizeX-1;
  631.     pt_corner[2].y = 0;
  632.     pt_corner[3].x = screenSizeX-1;
  633.     pt_corner[3].y = screenSizeY-1;
  634.  
  635.     while(!stop_draw_thread){
  636.         if(point_buffer_filled){
  637.             // redraw old pyramid in black
  638.             GpiSetColor(hps, CLR_BLACK);
  639.             for(j=0;j<4;j++){
  640.                 GpiMove(hps, &pt[i]);
  641.                 GpiLine(hps, &pt_corner[j]);
  642.             }
  643.         }
  644.  
  645.         // select random color
  646.         GpiSetColor(hps, ((unsigned)rand()) % 16);
  647.  
  648.         // select random point and store it in buffer
  649.         pt[i].x = ((unsigned)rand()) % screenSizeX;
  650.         pt[i].y = ((unsigned)rand()) % screenSizeY;
  651.  
  652.         // draw pyramid
  653.         for(j=0;j<4;j++){
  654.             GpiMove(hps, &pt[i]);
  655.             GpiLine(hps, &pt_corner[j]);
  656.         }
  657.  
  658.         // move circular buffer index
  659.         i++;
  660.         if(i == configuration_data.count)
  661.             point_buffer_filled = TRUE;
  662.         i %= configuration_data.count;
  663.  
  664.         // sleep if necessary
  665.         if(low_priority == FALSE)
  666.             DosSleep(1);
  667.  
  668.         // sleep if user requests slower animation
  669.         switch(configuration_data.animation_speed){
  670.         case 4: break;
  671.         case 3: DosSleep(10); break;
  672.         case 2: DosSleep(30); break;
  673.         case 1: DosSleep(50); break;
  674.         case 0: DosSleep(70); break;
  675.         }
  676.     }
  677.  
  678.     // free resources
  679.  
  680.  
  681.     DosUnsetExceptionHandler(&xcpthand);
  682.     WinDestroyMsgQueue(drawingthread_hmq);
  683.     WinTerminate(drawingthread_hab);
  684. */
  685.     _endthread();
  686. }
  687.